/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ve.usb.cep.actions;

import java.util.ArrayList;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ActionContext;
import java.util.HashMap;
import java.util.Map;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts2.ServletActionContext;
import com.google.gson.Gson;

import ve.usb.cep.db.SelectObject;
import ve.usb.cep.util.sqlWhere;
import ve.usb.cep.db.domainObjects.Oferta;
import ve.usb.cep.db.domainObjects.Curso;
import ve.usb.cep.db.domainObjects.Seccion;
import ve.usb.cep.db.domainObjects.Inscripcion;
import ve.usb.cep.db.domainObjects.Usuario;
import ve.usb.cep.db.domainObjects.Pago;
import ve.usb.cep.db.models.OfertaModel;
import ve.usb.cep.db.models.CursoModel;
import ve.usb.cep.db.models.SeccionModel;
import ve.usb.cep.db.models.InscripcionModel;
import ve.usb.cep.db.models.PagoModel;
import ve.usb.cep.db.models.UsuarioModel;
import ve.usb.cep.db.modelExceptions.OfertaException;
import ve.usb.cep.db.modelExceptions.CursoException;
import ve.usb.cep.db.modelExceptions.SeccionException;
import ve.usb.cep.db.modelExceptions.InscripcionException;
import ve.usb.cep.db.modelExceptions.PagoException;
import ve.usb.cep.db.modelExceptions.UsuarioException;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import ve.usb.cep.db.Session;


/**
 *
 * @author Andras
 */
public class InscripcionA extends ActionSupport{
	protected String iinscribir;
    protected String jinscribir;
    protected String hinscribir;
    protected HashMap err = new HashMap();
    protected String output = "";

    public String multiCrear(){
        //TODO: explicarle al usuario que NO es un error interno. Es su culpa.
        Usuario u = (Usuario) ActionContext.getContext().getSession().get("user");
        if (null == u){
            err.put("error", "Debe iniciar sesión para inscribir un curso");
            return "error";
        }
        System.out.println("*************************ESTA ES UNA PRUEBA***************");
        System.out.println("ESTA ES LA LISTA DE INSCRIPCIONES"+hinscribir+"*****");
        System.out.println("ESTA ES LA LISTA DE NUMEROS"+iinscribir+"*****");
        System.out.println("ESTA ES LA LISTA DE MONTOS"+jinscribir+"*****");
        String[] ofertas = hinscribir.split(",");
        String[] nros = iinscribir.split(",");
        String[] montos = jinscribir.split(",");
        ArrayList<Oferta> ao;
        ArrayList<Inscripcion> ai = new ArrayList<Inscripcion>();
        //Validar las ofertas solicitadas
        try{
            sqlWhere[] wpa = new sqlWhere[1];
            sqlWhere w = new sqlWhere(), wp = new sqlWhere();
            sqlWhere.rule[] r = new sqlWhere.rule[ofertas.length],
                            rp = new sqlWhere.rule[1];
            w.setGroupOp("OR");
            wp.setGroupOp("AND");
            int i = 0;
            for (String codigo : ofertas){
                r[i] = w.new rule();
                r[i].setField("oferta.codigo");
                r[i].setOp("eq");
                r[i].setData(codigo);
                i ++;
            }
            w.setRules(r);
            //Agregar las condiciones OR del código de la oferta
            wpa[0] = w;
            wp.setGroups(wpa);
            //Pedir que esté abierta siempre
            rp[0] = wp.new rule();
            rp[0].setField("abierto");
            rp[0].setOp("eq");
            rp[0].setData("1");
            wp.setRules(rp);

            ao = new OfertaModel().getCustom(
                    //TODO: especificar que sin límite
                    new SelectObject((short) 1000, (short) 1, "", "", wp)
            );
        }catch(OfertaException e){
            return _finishWithExceptions(e);
        }
        //TODO: explicarle al usuario que NO es un error interno. Es su culpa.
        if (0 == ao.size()){
            err.put("error", "No seleccionó ningún curso");
            return "error";
        }
        //Crear las inscripciones
        for (String codigo : ofertas){
            Oferta o = null;
            for (Oferta co : ao){
                if (co.getCodigo() == Integer.parseInt(codigo)){
                    o = co;
                }
            }
            //El curso no era válido
            if (null == o) continue;
            Inscripcion i = new Inscripcion();
            i.setConfirmada((short) 0);
            i.setEstudiante(u.getCodigo());
            i.setOferta(o.getCodigo());
            i.setCurso(o.getCurso());
            i.setPago(-1);
            ai.add(i);
        }
        //Encontrar los cursos para registrar el costo
        ArrayList<Curso> ac;
        try{
            sqlWhere w = new sqlWhere();
            sqlWhere.rule[] r = new sqlWhere.rule[ao.size()];
            w.setGroupOp("OR");
            int i = 0;
            for (Oferta o : ao){
                r[i] = w.new rule();
                r[i].setField("codigo");
                r[i].setOp("eq");
                r[i].setData(Integer.toString(o.getCurso()));
                i ++;
            }
            w.setRules(r);
            ac = new CursoModel().getCustom(
                    //TODO: especificar que sin límite
                    new SelectObject((short) 1000, (short) 1, "", "", w)
            );
        }catch(CursoException e){
            return _finishWithExceptions(e);
        }

        InscripcionModel im = new InscripcionModel();
		PagoModel pm = new PagoModel();
        //Agregar los costos para cada curso y crearlos
		int indiceDep = 0;
        for (Inscripcion i : ai){
            Curso c = null;
            for (Curso cc : ac){
                if (cc.getCodigo() == i.getCurso()){
                    c = cc;
                }
            }
            //El curso no era válido
            if (null == c) continue;
            i.setCosto(c.getCosto());
            try{
                im.add(i);
				
				Connection conn = Session.connection();
				ResultSet rs;
				PreparedStatement pstmt;
				pstmt = conn.prepareStatement("select * from inscripcion where oferta = ? and estudiante = ?");
                pstmt.setInt(1,i.getOferta());
                pstmt.setInt(2,u.getCodigo());
                rs = pstmt.executeQuery();
                if (rs.next()) {
                    //COMIENZA PARTE PAGO
                    //System.out.println("********Y LA LONGITUD DEL ARREGLO ES DE: "+nros.length+"***");
                    String nroDeposito = nros[indiceDep];
                    if (!nroDeposito.equals("NO")) {
                        System.out.println("ENTRA AL IF DE NRODEPOSITO!=NULL!*****"+nroDeposito+"****");
                        Pago p = new Pago();
                        p.setVoucher(nroDeposito);
                        //p.setValidadoPor(5);
                        p.setMonto(Integer.parseInt(montos[indiceDep].replaceAll(" ", "")));
                        System.out.println("AGREGA EL PAGO DE NRODEPOSITO = "+nroDeposito);
                        //p.setConforme((short) -1);
                        //p.setDescripcion("NE");
                        System.out.println("AGREGA EL PAGO DE MONTO = "+Integer.parseInt(montos[indiceDep].replaceAll(" ", "")));
                        p.setInscripcion(rs.getInt("codigo"));
                        System.out.println("AGREGA EL PAGO DE INSCRIPCION = "+rs.getInt("codigo"));
                        pm.add(p); 
                        System.out.println("**********AGREGA EL PAGO**************");
                    }
                    indiceDep = indiceDep + 1;
                }
				
				pstmt = conn.prepareStatement("select * from seccion where codigo_oferta = ? and numero = (select max(numero) from seccion where codigo_oferta = ?)");
				pstmt.setInt(1,i.getOferta());
				pstmt.setInt(2,i.getOferta());
				rs = pstmt.executeQuery();
				
				if (!rs.next()) {
					Seccion s = new Seccion();
					SeccionModel sm = new SeccionModel();
					s.setNumero(1);
					s.setMaxEstudiantes((short) 20); //Se debe poner el maxestudiantes indicado en la oferta
					s.setCodigoOferta(i.getOferta());
					sm.add(s);
					
					//Buscar codigo de la seccion creada
					pstmt = conn.prepareStatement("select codigo from seccion where codigo_oferta = ?");
					pstmt.setInt(1,i.getOferta());
					rs = pstmt.executeQuery();
					rs.next();
					
					//Agregar la inscripcion del estudiante en la seccion
					pstmt = conn.prepareStatement("insert into inscritos_seccion" +
						"(codigo_seccion, codigo_estudiante) values (?,?)");
					pstmt.setInt(1,rs.getInt(1));
					pstmt.setInt(2,i.getEstudiante());
					pstmt.executeUpdate();
				} else {
					int cantidadEstudiantes;
					Seccion s = new Seccion(rs.getInt("codigo"),
											rs.getInt("numero"),
											rs.getShort("max_estudiantes"),
											rs.getInt("codigo_oferta"),
											rs.getInt("codigo_prof"),
											rs.getString("aula"));
					
					pstmt = conn.prepareStatement("select count(*) from inscritos_seccion where codigo_seccion = ?");
					pstmt.setInt(1,s.getCodigo());
					rs = pstmt.executeQuery();
					rs.next();
					cantidadEstudiantes = rs.getInt(1);
					
					if (cantidadEstudiantes < s.getMaxEstudiantes()) {
						pstmt = conn.prepareStatement("insert into inscritos_seccion " +
						"(codigo_seccion, codigo_estudiante) values (?,?)");
						pstmt.setInt(1,s.getCodigo());
						pstmt.setInt(2,i.getEstudiante());
						pstmt.executeUpdate();
					} else {
						Seccion s2 = new Seccion();
						SeccionModel sm = new SeccionModel();
						int numeroSeccion = s.getNumero() + 1;
						s2.setNumero(numeroSeccion);
						s2.setMaxEstudiantes((short) 20); //Se debe poner el maxestudiantes indicado en la oferta
						s2.setCodigoOferta(i.getOferta());
						sm.add(s2);
						
						//Buscar codigo de la seccion creada
						pstmt = conn.prepareStatement("select codigo from seccion where codigo_oferta = ? and numero = ?");
						pstmt.setInt(1,i.getOferta());
						pstmt.setInt(2,numeroSeccion);
						rs = pstmt.executeQuery();
						rs.next();
						
						//Agregar la inscripcion del estudiante en la seccion
						pstmt = conn.prepareStatement("insert into inscritos_seccion" +
							"(codigo_seccion, codigo_estudiante) values (?,?)");
						pstmt.setInt(1,rs.getInt(1));
						pstmt.setInt(2,i.getEstudiante());
						pstmt.executeUpdate();
					}
				}
			} catch(PagoException e){
                return _finishWithExceptions(e);
            } catch(InscripcionException e){
                return _finishWithExceptions(e);
            } catch(SeccionException e){
                return _finishWithExceptions(e);
            } catch(java.sql.SQLException e){
		e.printStackTrace();
            }
        }
        return "success";
    }

    public String listar(){
        InscripcionModel mins = new InscripcionModel();
        SelectObject s;
        ArrayList<Inscripcion> inscripciones;
        int rowCount;
        try{
            s = _createSearchObject();
            if (!err.isEmpty()){
                return _finish();
            }
            mins = new InscripcionModel();
            inscripciones = mins.getCustom(s);
            rowCount = mins.getRowCount();
        }catch (InscripcionException e){
            return _finishWithExceptions(e);
        }
        if (!err.isEmpty()){
            return _finish();
        }

        HashMap[] m = new HashMap[inscripciones.size()];
        int i = 0;

        sqlWhere woferta = new sqlWhere();
        sqlWhere.rule[] boferta = new sqlWhere.rule[inscripciones.size()];
        sqlWhere wusuario = new sqlWhere();
        sqlWhere.rule[] busuario = new sqlWhere.rule[inscripciones.size()];
        sqlWhere wpago = new sqlWhere();
        sqlWhere.rule[] bpago = new sqlWhere.rule[inscripciones.size()];
        sqlWhere wcurso = new sqlWhere();
        sqlWhere.rule[] bcurso = new sqlWhere.rule[inscripciones.size()];
        for (Inscripcion rins : inscripciones){
            String[] c = new String[7];
            c[0] = Integer.toString(rins.getOferta());
            c[1] = Integer.toString(rins.getEstudiante());
            c[2] = Integer.toString(rins.getPago());
            c[3] = Integer.toString(rins.getConfirmada());
            c[4] = rins.getDescripcion();
            c[5] = Integer.toString(rins.getCosto());
            c[6] = Integer.toString(rins.getCurso());
            HashMap e = new HashMap();
            e.put("id", rins.getCodigo());
            e.put("cell", c);
            m[i] = e;

            boferta[i] = woferta.new rule();
            boferta[i].setField("oferta.codigo");
            boferta[i].setOp("eq");
            boferta[i].setData(c[0]);

            busuario[i] = wusuario.new rule();
            busuario[i].setField("codigo");
            busuario[i].setOp("eq");
            busuario[i].setData(c[1]);

            bpago[i] = wpago.new rule();
            bpago[i].setField("codigo");
            bpago[i].setOp("eq");
            bpago[i].setData(c[2]);

            bcurso[i] = wcurso.new rule();
            bcurso[i].setField("codigo");
            bcurso[i].setOp("eq");
            bcurso[i].setData(c[6]);

            ++ i;
        }

        woferta.setGroupOp("OR");
        woferta.setRules(boferta);
        ArrayList<Oferta> ofertas;
        try{
            ofertas = new OfertaModel().getCustom(
                new SelectObject(
                    (short) inscripciones.size(),
                    (short) 1,
                    "",
                    "",
                    woferta
                )
            );
        }catch(OfertaException e){
            return _finishWithExceptions(e);
        }
        i = 0;
        for (Inscripcion ins : inscripciones){
            for (Oferta o : ofertas){
                if (ins.getOferta() == o.getCodigo()){
                    ((String[]) m[i].get("cell"))[0] = o.getDias();
                }
            }
            ++ i;
        }

        wusuario.setGroupOp("OR");
        wusuario.setRules(busuario);
        ArrayList<Usuario> usuarios;
        try{
            usuarios = new UsuarioModel().getCustom(
                new SelectObject(
                    (short) inscripciones.size(),
                    (short) 1,
                    "",
                    "",
                    wusuario
                )
            );
        }catch(UsuarioException e){
            return _finishWithExceptions(e);
        }
        i = 0;
        for (Inscripcion ins : inscripciones){
            for (Usuario u : usuarios){
                if (ins.getEstudiante() == u.getCodigo()){
                    ((String[]) m[i].get("cell"))[1] = u.getNombre() + " " + u.getApellido();
                }
            }
            ++ i;
        }

        wpago.setGroupOp("OR");
        wpago.setRules(bpago);
        ArrayList<Pago> pagos;
        try{
            pagos = new PagoModel().getCustom(
                new SelectObject(
                    (short) inscripciones.size(),
                    (short) 1,
                    "",
                    "",
                    wpago
                )
            );
        }catch(PagoException e){
            return _finishWithExceptions(e);
        }
        i = 0;
        for (Inscripcion ins : inscripciones){
            for (Pago p : pagos){
                if (ins.getPago() == p.getCodigo()){
                    ((String[]) m[i].get("cell"))[2] = p.getVoucher();
                }
            }
            ++ i;
        }

        wcurso.setGroupOp("OR");
        wcurso.setRules(bcurso);
        ArrayList<Curso> cursos;
        try{
            cursos = new CursoModel().getCustom(
                new SelectObject(
                    (short) inscripciones.size(),
                    (short) 1,
                    "",
                    "",
                    wcurso
                )
            );
        }catch(CursoException e){
            return _finishWithExceptions(e);
        }
        i = 0;
        for (Inscripcion ins : inscripciones){
            for (Curso p : cursos){
                if (ins.getCurso() == p.getCodigo()){
                    ((String[]) m[i].get("cell"))[6] = p.getNombre();
                }
            }
            ++ i;
        }

        HashMap r = new HashMap();
        r.put("total", Math.ceil((double) rowCount / (double) s.getRows()));
        r.put("page", s.getPage());
        r.put("records", s.getRows());
        r.put("rows", m);
 
        output = new Gson().toJson(r);

        return SUCCESS;
    }
    
    public String eliminar(){

        HttpServletRequest r = ServletActionContext.getRequest();
        int codigo = 0;
        try{
            codigo = Integer.parseInt(r.getParameter("id"));
        }catch(java.lang.NumberFormatException e){
            err.put("Código", "El registro con el número '" + r.getParameter("id") + "' no existe.");
        }

        if (!err.isEmpty()){
            return _finish();
        }

        try{
            new InscripcionModel().delete(codigo);
            return _finish();
        }catch (InscripcionException e){
            return _finishWithExceptions(e);
        }
    }

    protected SelectObject _createSearchObject()
        throws InscripcionException
    {

        HttpServletRequest r = ServletActionContext.getRequest();
        sqlWhere w = (sqlWhere) new Gson().fromJson(
                r.getParameter("filters"), sqlWhere.class);
        if (null == w){
            w = new sqlWhere();
        }

        //Convertir la búsqueda del nombre en la búsqueda de enteros
        if (null != w.getRules()){
            for (sqlWhere.rule c : w.getRules()){
                if ("oferta".equals(c.getField())){
                    c.setData(Integer.toString(_getCodigoFromOferta(c.getData())));
                }
                if ("estudiante".equals(c.getField())){
                    c.setData(Integer.toString(_getCodigoFromUsuario(c.getData())));
                }
                if ("pago".equals(c.getField())){
                    c.setData(Integer.toString(_getCodigoFromPago(c.getData())));
                }
                if ("curso".equals(c.getField())){
                    c.setData(Integer.toString(_getCodigoFromCurso(c.getData())));
                }
            }
        }

        short rows = 20, page = 1;
        try{
            rows = (short) Integer.parseInt(r.getParameter("rows"));
            page = (short) Integer.parseInt(r.getParameter("page"));
        }catch(java.lang.NumberFormatException e){
            
        }
        return new SelectObject(
            rows,
            page,
            r.getParameter("sidx"),
            r.getParameter("sord"),
            w
        );
    }

    protected int _getCodigoFromCurso(String curso)
        throws InscripcionException
    {

        sqlWhere w = new sqlWhere();
        sqlWhere.rule[] c = new sqlWhere.rule[1];
        c[0] = w.new rule();
        c[0].setField("nombre");
        c[0].setOp("eq");
        c[0].setData(curso);
        w.setRules(c);

        ArrayList<Curso> cursos = null;
        try{
            cursos = new CursoModel().getCustom(new SelectObject((short) 1,
                    (short) 1,
                    "nombre",
                    "asc",
                    w
            ));
        }catch (CursoException e){
            throw new InscripcionException("Error en cursos: " + e.getMessage());
        }
 
        if (null == cursos || 0 == cursos.size()){
            err.put("Curso", "El curso '" + curso + "' no existe");
            return -1;
        }

        return cursos.get(0).getCodigo();
    }

    protected int _getCodigoFromPago(String pago)
        throws InscripcionException
    {

        sqlWhere w = new sqlWhere();
        sqlWhere.rule[] c = new sqlWhere.rule[1];
        c[0] = w.new rule();
        c[0].setField("voucher");
        c[0].setOp("eq");
        c[0].setData(pago);
        w.setRules(c);

        ArrayList<Pago> pagos = null;
        try{
            pagos = new PagoModel().getCustom(new SelectObject((short) 1,
                    (short) 1,
                    "voucher",
                    "asc",
                    w
            ));
        }catch (PagoException e){
            throw new InscripcionException("Error en cursos: " + e.getMessage());
        }
 
        if (null == pagos || 0 == pagos.size()){
            err.put("Curso", "El pago '" + pago + "' no existe");
            return -1;
        }

        return pagos.get(0).getCodigo();
    }

    protected int _getCodigoFromUsuario(String usuario)
        throws InscripcionException
    {

        sqlWhere w = new sqlWhere();
        sqlWhere.rule[] c = new sqlWhere.rule[1];
        c[0] = w.new rule();
        c[0].setField("(nombre||' '||apellido)");
        c[0].setOp("eq");
        c[0].setData(usuario);
        w.setRules(c);

        ArrayList<Usuario> usuarios = null;
        try{
            usuarios = new UsuarioModel().getCustom(new SelectObject((short) 1,
                    (short) 1,
                    "",
                    "",
                    w
            ));
        }catch (UsuarioException e){
            throw new InscripcionException("Error en usuarios: " + e.getMessage());
        }
 
        if (null == usuarios || 0 == usuarios.size()){
            err.put("Curso", "El pago '" + usuario + "' no existe");
            return -1;
        }

        return usuarios.get(0).getCodigo();
    }

    protected int _getCodigoFromOferta(String oferta)
        throws InscripcionException
    {

        sqlWhere w = new sqlWhere();
        sqlWhere.rule[] c = new sqlWhere.rule[1];
        c[0] = w.new rule();
        c[0].setField("dias");
        c[0].setOp("eq");
        c[0].setData(oferta);
        w.setRules(c);

        ArrayList<Oferta> ofertas = null;
        try{
            ofertas = new OfertaModel().getCustom(new SelectObject((short) 1,
                    (short) 1,
                    "",
                    "",
                    w
            ));
        }catch (OfertaException e){
            throw new InscripcionException("Error en ofertas: " + e.getMessage());
        }
 
        if (null == ofertas || 0 == ofertas.size()){
            err.put("Curso", "La oferta en el día '" + oferta + "' no existe");
            return -1;
        }

        return ofertas.get(0).getCodigo();
    }

    public void setHinscribir(String hinscribir){
        this.hinscribir = hinscribir;
    }

	public void setIinscribir(String iinscribir){
        this.iinscribir = iinscribir;
    }
    
    public void setJinscribir(String jinscribir){
        this.jinscribir = jinscribir;
    }
	
    protected String _finishWithExceptions(Exception e){
        ServletActionContext.getResponse()
                .setStatus(HttpServletResponse.SC_BAD_REQUEST);

        //Para los casos en los que el error sea interno, err estará vacío.
        if (null != e){
            e.printStackTrace();
            err.put("error interno", e.getMessage());
            output = new Gson().toJson(err);
        }
        return ERROR;
    }

    protected String _finish(){
        if (!err.isEmpty()){
            ServletActionContext.getResponse()
                .setStatus(HttpServletResponse.SC_BAD_REQUEST);
            output = new Gson().toJson(err);
            return ERROR;
        }

        return SUCCESS;
    }

    //Output, salida estándar por texto
    public String getOutput() {
        return output;
    }
    public String getError(){
        Iterator it = err.entrySet().iterator();
        String error = "";
        while (it.hasNext()) {
            Map.Entry pairs = (Map.Entry) it.next();
            error += "<li><b>" + pairs.getKey() + "</b>: " + pairs.getValue() + "</li>";
        }
        return error;
    }
}
